package com.boom.monitor.service;

import com.boom.common.utils.StringUtils;
import com.boom.monitor.DTO.SnmpDTO;
import com.boom.monitor.VO.snmp.Process;
import com.boom.monitor.VO.snmp.*;
import com.boom.monitor.util.FormatterUnitUtils;
import com.boom.monitor.util.SnmpConst;
import com.boom.monitor.util.SnmpUtils;
import org.snmp4j.PDU;
import org.snmp4j.smi.VariableBinding;
import org.snmp4j.util.TableEvent;

import java.text.DecimalFormat;
import java.util.*;

/**
 * @author:yzw
 * @Date:2021/4/6 下午2:22
 * @desc:
 * @version:1.0
 */
public class BoomSnmpService {

	/**
	 * 信息概览
	 * @param dto
	 * @return com.boom.monitor.VO.snmp.Overview
	 * @author yzw
	 * @time 2021/4/7 下午8:59
	 */
	public static SnmpOverview getOverView(SnmpDTO dto) {
		return new SnmpOverview(getSystemInfo(dto), getStoreInfo(dto), getCpuInfo(dto));
	}

	/**
	 * 系统信息
	 *
	 * @param dto
	 * @return java.util.Map<java.lang.String, java.lang.String>
	 * @author yzw
	 * @time 2021/4/6 下午3:36
	 */
	public static Map<String, String> getSystemInfo(SnmpDTO dto) {
		Map<String, String> result = new HashMap<>();
		Collection<String> oIds = SnmpConst.SYSTEM_INFO_MAP.keySet();
		PDU pdu = SnmpUtils.getPduResponse(dto, new ArrayList<>(oIds));
		if (pdu != null && pdu.size() > 0) {
			for (int i = 0; i < pdu.size(); i++) {
				String[] values = pdu.get(i).toString().split(" =");
				String value = StringUtils.trim(values[1]);
				value = StringUtils.equals(value, "noSuchInstance")
						|| StringUtils.equals(value, "noSuchObject")
						|| StringUtils.isEmpty(value) ? "n/a" : value;
				result.put(SnmpConst.SYSTEM_INFO_MAP.get(values[0]), value);
			}
		}
		return result;
	}

	/**
	 * 获取存储信息（磁盘和内存）
	 *
	 * @param dto
	 * @return java.util.List<com.boom.monitor.VO.snmp.Disk>
	 * @author yzw
	 * @time 2021/4/7 上午11:16
	 */
	public static Store getStoreInfo(SnmpDTO dto) {
		Store store = new Store();
		List<Disk> disks = new ArrayList<>();
		String diskOid = "1.3.6.1.2.1.25.2.1.4";
		String physicalMemoryOid = "1.3.6.1.2.1.25.2.1.2";
		// 存储单元类型\存储单元大小\总存储单元数\使用存储单元数
		List<String> oIds = Arrays.asList(
				"1.3.6.1.2.1.25.2.3.1.2",
				"1.3.6.1.2.1.25.2.3.1.3",
				"1.3.6.1.2.1.25.2.3.1.4",
				"1.3.6.1.2.1.25.2.3.1.5",
				"1.3.6.1.2.1.25.2.3.1.6"
		);
		List<TableEvent> tableEventList = SnmpUtils.walkResponseTableEvents(dto, oIds);
		if (tableEventList != null) {
			for (TableEvent event : tableEventList) {
				VariableBinding[] values = event.getColumns();
				if (values == null) {
					continue;
				}
				String oid = values[0].getVariable().toString();
				if (StringUtils.equals(diskOid, oid) || StringUtils.equals(oid, physicalMemoryOid)) {
					int unit = Integer.parseInt(values[2].getVariable().toString());
					int totalSize = Integer.parseInt(values[3].getVariable().toString());
					int usedSize = Integer.parseInt(values[4].getVariable().toString());
					String total = FormatterUnitUtils.formatterUnit((long) totalSize * unit);
					String used = FormatterUnitUtils.formatterUnit((long) usedSize * unit);
					DecimalFormat format = new DecimalFormat("#0.0");
					String rate = format.format((double) usedSize / totalSize * 100) + "%";
					String name = values[1].getVariable().toString();
					if (StringUtils.equals(diskOid, oid)) {
						Disk disk = new Disk();
						disk.setName(name);
						disk.setTotal(total);
						disk.setUsed(used);
						disk.setRate(rate);
						disks.add(disk);
					} else if (StringUtils.equals(oid, physicalMemoryOid)) {
						Memory memory = new Memory();
						memory.setName(name);
						memory.setTotal(total);
						memory.setUsed(used);
						memory.setRate(rate);
						store.setMemory(memory);
					}
				}
			}
		}
		store.setDisks(disks);
		return store;
	}

	/**
	 * 获取Cpu信息
	 *
	 * @param dto
	 * @return java.util.List<com.boom.monitor.VO.snmp.Cpu>
	 * @author yzw
	 * @time 2021/4/7 上午11:16
	 */
	public static List<Cpu> getCpuInfo(SnmpDTO dto) {
		List<Cpu> cpus = new ArrayList<>();
		List<TableEvent> tableEventList = SnmpUtils.walkResponseTableEvents(dto, Collections.singletonList("1.3.6.1.2.1.25.3.3.1.2"));
		if (tableEventList != null) {
			for (int i = 0; i < tableEventList.size(); i++) {
				VariableBinding[] values = tableEventList.get(i).getColumns();
				if (values != null) {
					cpus.add(new Cpu("cpu" + (i + 1), values[0].getVariable().toString() + "%"));
				}
			}
		}
		return cpus;
	}

	/**
	 * 获取进程信息
	 *
	 * @param dto
	 * @return java.util.List<com.boom.monitor.VO.snmp.Process>
	 * @author yzw
	 * @time 2021/4/7 下午1:52
	 */
	public static List<Process> getProcessInfo(SnmpDTO dto) {
		List<Process> processes = new ArrayList<>();
		// name/run path/cpu/memory/pid
		List<String> oIds = Arrays.asList(
				"1.3.6.1.2.1.25.4.2.1.2",
				"1.3.6.1.2.1.25.4.2.1.4",
				"1.3.6.1.2.1.25.5.1.1.1",
				"1.3.6.1.2.1.25.5.1.1.2",
				"1.3.6.1.2.1.25.4.2.1.1"
		);
		List<TableEvent> tableEventList = SnmpUtils.walkResponseTableEvents(dto, oIds);
		if (tableEventList != null) {
			for (TableEvent event : tableEventList) {
				VariableBinding[] values = event.getColumns();
				if (values == null) {
					continue;
				}
				String name = values[0].getVariable().toString();
				String path = values[1].getVariable().toString();
				long cpu = Long.parseLong(values[2].getVariable().toString());
				long memory = Long.parseLong(values[3].getVariable().toString());
				String pid = values[4].getVariable().toString();
				if (cpu != 0 && memory != 0) {
					processes.add(new Process(name, cpu, memory, path, pid));
				}
			}
		}
		// 根据占用CPU进行降序排列
		processes.sort((o1, o2) -> Math.toIntExact(o2.getUseCpu() - o1.getUseCpu()));
		return processes;
	}
}
